package net.cloudcodex.shared.rpc;

import java.util.Date;
import java.util.List;
import java.util.Map;

import net.cloudcodex.shared.Errors;
import net.cloudcodex.shared.MessageAction;
import net.cloudcodex.shared.dto.Result;
import net.cloudcodex.shared.dto.campaign.character.CharacterDescriptionDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterHeaderDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterNoteDTO;
import net.cloudcodex.shared.dto.campaign.character.CompleteCharacterDescriptionDTO;
import net.cloudcodex.shared.dto.home.CampaignSummaryDTO;
import net.cloudcodex.shared.dto.msg.SceneDTO;
import net.cloudcodex.shared.dto.msg.SceneToCreateDTO;

import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * The async counterpart of <code>CampaignRPC</code>.
 */
public interface CampaignRPCAsync {

	/**
	 * Creates a campaign.
	 * 
	 * @param name
	 *            name of the campaign to create.
	 * @param game
	 *            game of the campaign to create.
	 * @param description
	 *            campaign's description, visible before joining it.
	 * @param icon
	 *            url for the campaign's icon.
	 * @return the newly created campaign.
	 * @see Errors#IMPOSSIBLE_EXISTS
	 */
	public void createCampaign(String name, String game, String description, String icon,
			AsyncCallback<Result<CampaignSummaryDTO>> callback);

	/**
	 * Updates a campaign. Be careful, notifications and characters are not
	 * re-read and then not returned here.
	 * 
	 * @param campaign
	 *            id of the campaign to update.
	 * @param name
	 *            name of the campaign to create.
	 * @param game
	 *            game of the campaign to create.
	 * @param description
	 *            campaign's description, visible before joining it.
	 * @param icon
	 *            url for the campaign's icon.
	 * @return the newly created campaign.
	 * @see Errors#IMPOSSIBLE_EXISTS if the name is already used
	 */
	public void updateCampaign(long campaignId, String name, String game, String description, String icon,
			AsyncCallback<Result<CampaignSummaryDTO>> callback);

	/**
	 * Gives the last messages of the campaign for a character.
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param lastSceneId
	 *            for pagination, your last scene read. may be null.
	 * @param timestamp
	 *            for delta, your last update date. When not null, lastSceneId
	 *            is not used.
	 * @return the last messages of the characters. scenes are limited but
	 *         complete.
	 */
	public void getMessages(long campaignId, long characterId, Long lastSceneId, Date timestamp,
			AsyncCallback<Result<List<SceneDTO>>> callback);

	/**
	 * Temporary method to invit someone to a campaign.
	 * 
	 * @param campaignId
	 *            campaign id.
	 * @param email
	 *            email of the user.
	 * @param name
	 *            Name of the character to create.
	 * @return the created character
	 * @see Errors#IMPOSSIBLE_EXISTS
	 * @see Errors#IMPOSSIBLE_ITSELF
	 */
	public void inviteToCampaign(long campaignId, String email, String name,
			AsyncCallback<Result<CharacterHeaderDTO>> callback);

	/**
	 * Creates a NPC.
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param name
	 *            NPC's name.
	 * @param description
	 *            NPC's public description, can be null.
	 * @param icon
	 *            NPC's icon, can be null;
	 * @param profile
	 *            <code>true</code> for profiles.
	 * @return the NPC's header to update client cache.
	 * @see Errors#IMPOSSIBLE_EXISTS
	 */
	public void addNPC(long campaignId, String name, String description, String icon, boolean profile,
			AsyncCallback<Result<CharacterHeaderDTO>> callback);

	/**
	 * Loads the campaign's characters. Only GM cans call this method.
	 * Characters are not sorted. TODO pagination ?
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @return the campaign's characters.
	 */
	public void getCampaignCharacters(long campaignId, AsyncCallback<Result<List<CharacterHeaderDTO>>> callback);

	/**
	 * Returns the character description :
	 * <ul>
	 * <li>Your note if you are a player,
	 * <li>All the notes if you are the GM.
	 * </ul>
	 * If you specify a timestamp, only changes are returned, so may get a
	 * CharacterDescription with only one note if only one has been updated.
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param byCharacterId
	 *            the current character, who want to see the description.
	 *            <code>null</code> for GM. Of course, it shares the same
	 *            campaignId.
	 * @param timestamp
	 *            <code>null</code> the first time, the description timestamp
	 *            the next times; usefull for dealing with deltas.
	 * @return the character description.
	 */
	public void getCharacterDescription(long campaignId, long characterId, Long byCharacterId, Date timestamp,
			AsyncCallback<Result<CharacterDescriptionDTO>> callback);

	/**
	 * Use it to initialise a player story board with its character description
	 * (as viewable by itself) already completely loaded. Only character's owner
	 * can call this method.
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            the current character's id.
	 * @return the complete character description.
	 */
	public void getCharacterCompleteDescription(long campaignId, long characterId,
			AsyncCallback<Result<CompleteCharacterDescriptionDTO>> callback);

	/**
	 * Updates a character description :
	 * <ul>
	 * <li>Only GM can update the description and the sheet
	 * <li>GM can view and edit all aliases
	 * <li>GM can view and edit all notes
	 * <li>Character can update its own note about the character.
	 * </ul>
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param byCharacterId
	 *            the character updating its note about characterId
	 * @param description
	 *            description to update, if null : not updated, give empty
	 *            string to clear the description.
	 * @param sheet
	 *            character's sheet, if null : not updated, give empty string to
	 *            clear the sheet.
	 * @param notes
	 *            notes to update, to clear one note give null string as
	 *            content. For player, give only your own note, others notes
	 *            will not be used.
	 * @param aliases
	 *            GM only, modify "alias per PC".
	 * @param dead
	 *            if specified, indicates if the character is dead, only for GM.
	 * @param locked
	 *            if specified, indicates if the PC is locked, only for GM.
	 * @return updated data.
	 * @see Errors#IMPOSSIBLE_PROFILE
	 */
	public void updateCharacterDescription(long campaignId, long characterId, Long byCharacterId, String description,
			String sheet, Boolean dead, Boolean locked, List<CharacterNoteDTO> notes, Map<Long, String> aliases,
			AsyncCallback<Result<CharacterDescriptionDTO>> callback);

	/**
	 * Try to create the scenes as given. Only playable characters of the given
	 * scenes are updated, the others stay in their current scenes.
	 * 
	 * You cannot create a new scene for PC1 without dispatching PC2 in a new
	 * scene (may be the same) if they were together in the previous scene. All
	 * the playable characters of a scene, where an updated playable character
	 * was, must be dispatched.
	 * 
	 * Playable characters cannot have ubiquity, NPC can.
	 * 
	 * So, if : - PC1 + PC2 + NPC1 - PC3
	 * 
	 * You can do : - scene [0] : PC1 + NPC1 - scene [1] : PC2 + NPC1 - PC3
	 * (stays in its own scene).
	 * 
	 * @param campaignId
	 *            campaign's id
	 * @param scenes
	 *            new scenes (characters, intro and aliases).
	 * @return
	 * @see Errors#IMPOSSIBLE_UBIQUITY, Errors#IMPOSSIBLE_ONLY_NPCS,
	 *      Errors#IMPOSSIBLE_PC_NOT_DISPATCHED
	 */
	public void startScenes(long campaignId, SceneToCreateDTO[] scenes, AsyncCallback<Result<Boolean>> callback);

	/**
	 * Temporary test method. Be carefull because this method doesn't make lots
	 * a security checks.
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param action
	 *            <ul>
	 *            <li>0 : random
	 *            <li>1 : create a random sequence
	 *            <li>2 : make someone talk in current scene randomly
	 *            <li>3 : insert OFF message in previous scenes
	 *            <li>4 : delete one message randomly
	 *            <li>5 : make other players to roll dices (not visible :) )
	 *            <li>6 : force to reindex some messages in previous or current
	 *            scene.
	 *            </ul>
	 * @return
	 */
	public void justForTestsDoSomethingRandomly(long campaignId, long characterId, int action,
			AsyncCallback<Result<Boolean>> callback);

	/**
	 * The method called when player posts an action. <b>Only for players
	 * !!!!</b>
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param action
	 *            action type.
	 * @param content
	 *            text of the action.
	 * @return true if ok.
	 * @see Errors#IMPOSSIBLE_LOCKED, Errors#IMPOSSIBLE_DEAD, Errors#IMPOSSIBLE,
	 *      Errors#OUTOFDATE, Errors#IMPOSSIBLE_CLOSED,
	 *      Errors#IMPOSSIBLE_PAUSED,
	 */
	public void playerPostAction(long campaignId, long characterId, long clientSceneId, Date clientSceneTimestamp,
			MessageAction action, String content, AsyncCallback<Result<Boolean>> callback);

	/**
	 * The method called when player posts an OFF message. <b>Only for players
	 * !!!!</b>
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param content
	 *            text of the message.
	 * @return true if ok.
	 * @see Errors#IMPOSSIBLE_LOCKED, Errors#IMPOSSIBLE_DEAD, Errors#IMPOSSIBLE,
	 *      Errors#OUTOFDATE, Errors#IMPOSSIBLE_CLOSED,
	 *      Errors#IMPOSSIBLE_PAUSED,
	 */
	public void playerPostOFF(long campaignId, long characterId, long clientSceneId, Date clientSceneTimestamp,
			String content, AsyncCallback<Result<Boolean>> callback);

	/**
	 * The method called when player rolls dices. <b>Only for players !!!!</b>
	 * 
	 * @param campaignId
	 *            campaign's id.
	 * @param characterId
	 *            character's id.
	 * @param the
	 *            dices to roll : Map<Sides, NumberOfDices>
	 * @param content
	 *            text of the message.
	 * @return true if ok.
	 * @see Errors#IMPOSSIBLE_LOCKED, Errors#IMPOSSIBLE_DEAD, Errors#IMPOSSIBLE,
	 *      Errors#OUTOFDATE, Errors#IMPOSSIBLE_CLOSED,
	 *      Errors#IMPOSSIBLE_PAUSED,
	 */
	public void playerRollDices(long campaignId, long characterId, long clientSceneId, Date clientSceneTimestamp,
			Map<Integer, Integer> dices, String content, AsyncCallback<Result<Boolean>> callback);

}
